#include <stdio.h>
#include <assert.h>
#include "thread.h"
#include "sem2.h"

/*
 * Test des sémaphores.
 *
 * Les affichages doivent se faire dans le bon ordre.
 */

thread_sem_t * sem;

struct thfuncargs {
  char * tab;
  int ltab;
  int nbreads;
};

static void * thfunc(void * dummy)
{
  char c;
  int i, j;
  struct thfuncargs * thfcargs = (struct thfuncargs *)dummy;
  int semvalue;

  thread_sem_wait(sem);
  // Section critique
  thread_sem_getvalue(sem, &semvalue);
  printf("Le thread %p a commencé la lecture (sem = %d)\n", thread_self(), semvalue);
  for (i = 0; i < thfcargs->nbreads; i++)
  {
    for (j = 0; j < thfcargs->ltab; j++)
    {
      c = thfcargs->tab[j];
      thread_yield();
    }
  }
  printf("Le thread %p a lu %d fois\n", thread_self(), thfcargs->nbreads);
  thread_sem_post(sem);

  thread_exit(NULL);
}

int main(void)
{
  thread_t th1, th2, th3, th4;
  int err;
  int ltab = 10;
  char tab[ltab];
  int i;
  int semvalue;

  for (i = 0; i < ltab; i++)
    tab[i] = 'r';

  struct thfuncargs thfcargs1;
  thfcargs1.tab = tab;
  thfcargs1.ltab = ltab;
  thfcargs1.nbreads = 4;
  struct thfuncargs thfcargs2;
  thfcargs2.tab = tab;
  thfcargs2.ltab = ltab;
  thfcargs2.nbreads = 8;
  struct thfuncargs thfcargs3;
  thfcargs3.tab = tab;
  thfcargs3.ltab = ltab;
  thfcargs3.nbreads = 2;
  struct thfuncargs thfcargs4;
  thfcargs4.tab = tab;
  thfcargs4.ltab = ltab;
  thfcargs4.nbreads = 1;

  thread_sem_init(&sem, 2); // 2 threads à la fois peuvent lire le tableau

  thread_sem_getvalue(sem, &semvalue);
  printf("Le sémaphore a une valeur de %d\n", semvalue);

  err = thread_create(&th1, thfunc, &thfcargs1);
  assert(!err);
  err = thread_create(&th2, thfunc, &thfcargs2);
  assert(!err);
  err = thread_create(&th3, thfunc, &thfcargs3);
  assert(!err);
  err = thread_create(&th4, thfunc, &thfcargs4);
  assert(!err);

  err = thread_join(th2, NULL);
  assert(!err);
  err = thread_join(th1, NULL);
  assert(!err);
  err = thread_join(th4, NULL);
  assert(!err);
  err = thread_join(th3, NULL);
  assert(!err);

  thread_sem_destroy(sem);

  return 0;
}
